home *** CD-ROM | disk | FTP | other *** search
- /*
- ** U N A D O B E
- **
- ** Extract font PostScript code from a Macintosh font file resource fork
- ** (a procedure somewhat akin to extracting water out of rocks), basically
- ** the same function as the oldie unAdobe program on the Macintosh.
- ** In addition to this it does the job of the unfont (or pfbtopfa)
- ** program, that is, reads PC pfb format packed font files.
- **
- ** Information used in this program was acquired from:
- ** - Inside Macintosh I p.128: Format of a Resource File
- ** - Adobe TechNote #5040: Supporting Downloadable PostScript Language Fonts
- **
- ** BUGS: this code is specifically written for Motorola-endian machines (like
- ** Macintosh resource files also are); there is no provision for reading
- ** MacBinary-encoded Macintosh files (solution: get rid of 128 first bytes,
- ** for example with "dd", then feed file on stdin).
- **
- ** A million thanks to Rob Elliott <relliott@b11.b11.ingr.com> for pointing
- ** me in the correct direction on where to find the unpacking information and
- ** Mark Adler <madler@cco.caltech.edu> for telling me about the NeXT method
- ** of making the Macintosh file system resource fork available as .#rsrc#
- **
- ** Written by Otto J. Makela <otto@jyu.fi>
- ** Distributed under the GNU Public Licence -- see file COPYING for details
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- int verbose=0;
-
- main(int argc, char *argv[]) {
- int loop,i,files=0,type=0;
- FILE *fi,*fo;
-
- /* Loop thru all files given on command line */
- loop:
- for(loop=1; loop<argc; loop++) {
- /* Possible argument */
- if(*argv[loop]=='-')
- if(argv[loop][1]) {
- while(i=*++argv[loop])
- switch(i) {
- case 'm': type=1; break;
- case 'p': type=2; break;
- case 'v': verbose++; break;
- default: goto usage;
- }
- continue;
- } else {
- /* Bare dashes mean stdin/out */
- fi=stdin;
- fo=stdout;
- }
- else if(!(fi=fopen(argv[loop],"rb"))) {
- fprintf(stderr,"%s: can't open file \"%s\" for input\n",
- *argv,argv[loop]);
- exit(1);
- } else {
- char *p,filename[BUFSIZ];
-
- strcpy(filename,argv[loop]);
- /* On a NeXT you see Macintosh resource forks as .#rsrc# files */
- if(p=strstr(filename,".#rsrc#")) {
- *p='\0';
- if(!type) type=1;
- } else if(p=strstr(filename,".pfb")) {
- p[3]='a';
- if(!type) type=2;
- } else
- strcat(filename,".ps");
-
- if(!(fo=fopen(filename,"wt"))) {
- fprintf(stderr,"%s: can't open file \"%s\" for output\n",
- *argv,filename);
- exit(1);
- }
- }
-
- if(type==1) {
- if(verbose) fprintf(stderr,"Macintosh resource file %s:\n",argv[loop]);
- if(macfont(fi,fo)) {
- fprintf(stderr,"%s: EOF or data format errors reading file \"%s\"\n",
- *argv,argv[loop]);
- exit(1);
- }
- } else if(type==2) {
- if(verbose) fprintf(stderr,"PC pfb file %s:\n",argv[loop]);
- if(pcfont(fi,fo)) {
- fprintf(stderr,"%s: EOF or data format errors reading file \"%s\"\n",
- *argv,argv[loop]);
- exit(1);
- }
- } else {
- fprintf(stderr,"%s: could not determine file \"%s\" type\n",
- *argv,argv[loop]);
- usage:
- fprintf(stderr,"usage: %s [-mpv] fontfile...\n"
- "where the font file type is guessed from file extension or:\n"
- "-m\tSet Macintosh resource file format for next file\n"
- "-p\tSet PC pfb file format for next file\n"
- "-v\tIncrease verboseness (repeat for more)\n",*argv);
- exit(1);
- }
-
- if(fi!=stdin) fclose(fi);
- if(fo!=stdout) fclose(fo);
- type=0; files++;
- }
-
- /* If no arguments given, read stdin and output to stdout */
- if(!files) {
- argv[1]="-";
- argc=2;
- goto loop;
- }
-
- exit(0);
- }
-
-
- /*
- ** Read a Macintosh resource fork file
- */
- macfont(FILE *fi,FILE *fo) {
- int i;
-
- /* The following data represents a Macintosh resource fork structure */
- struct {
- unsigned long int data_offset;
- unsigned long int map_offset;
- unsigned long int data_length;
- unsigned long int map_length;
- } resourceheader;
- struct {
- unsigned char dummy0[16];
- unsigned long int dummy1;
- unsigned short int dummy2;
- unsigned short int resourcefile_attribute;
- unsigned short int typelist_offset;
- unsigned short int namelist_offset;
- } resourcemap;
- unsigned short type_count;
- struct {
- char resource_type[4];
- unsigned short int reference_count;
- unsigned short int referencelist_offset;
- } typelist;
- struct {
- unsigned short int resource_id;
- unsigned short int referencelist_offset;
- union {
- unsigned char resource_attribute;
- unsigned long data_offset;
- } reference;
- unsigned long int dummy3;
- } referencelist;
-
-
- /* First read main resource file header */
- if(fread(&resourceheader,1,sizeof(resourceheader),fi)!=
- sizeof(resourceheader))
- return(1);
-
- if(verbose) fprintf(stderr,
- "resource data\toffset = %lu\n"
- "\t\tlength = %lu\n"
- "resource map\toffset = %lu\n"
- "\t\tlength = %lu\n",
- resourceheader.data_offset,resourceheader.data_length,
- resourceheader.map_offset,resourceheader.map_length);
-
- fseek(fi,resourceheader.map_offset,0);
- if(fread(&resourcemap,1,sizeof(resourcemap),fi)!=sizeof(resourcemap))
- return(1);
-
- if(verbose) fprintf(stderr,
- "resourcefile attribute = %04x\n"
- "type list offset = %lu (absolute %lu)\n"
- "name list offset = %lu (absolute %lu)\n",
- resourcemap.resourcefile_attribute,
- resourcemap.typelist_offset,
- resourceheader.map_offset+resourcemap.typelist_offset,
- resourcemap.namelist_offset,
- resourceheader.map_offset+resourcemap.namelist_offset);
-
- fseek(fi,resourceheader.map_offset+resourcemap.typelist_offset,0);
- if(fread(&type_count,1,sizeof(type_count),fi)!=sizeof(type_count))
- return(1);
-
- /* Search for a POST resource containing the PostScript code */
- for(i=0; i<=type_count; i++) {
- if(fread(&typelist,1,sizeof(typelist),fi)!=sizeof(typelist))
- return(1);
- if(verbose)
- fprintf(stderr,"resource_type=\"%.4s\"\n",typelist.resource_type);
- if(!strncmp(typelist.resource_type,"POST",4)) break;
- }
-
- /* No POST resource was found */
- if(i>type_count) return(1);
-
- if(verbose) fprintf(stderr,
- "%.4s resources = %u\n"
- "%.4s reference list offset = %lu (absolute %lu)\n",
- typelist.resource_type,typelist.reference_count+1,
- typelist.resource_type,typelist.referencelist_offset,
- resourceheader.map_offset+resourcemap.typelist_offset+
- typelist.referencelist_offset);
-
- /* Loop thru the resources in numerical order */
- for(i=0; i<=typelist.reference_count; i++) {
- fseek(fi,resourceheader.map_offset+resourcemap.typelist_offset+
- typelist.referencelist_offset+i*sizeof(referencelist),0);
- if(fread(&referencelist,1,sizeof(referencelist),fi)!=
- sizeof(referencelist))
- return(1);
-
- if(verbose) fprintf(stderr,
- "resource_id = %u, attribute %02x\n",
- referencelist.resource_id,
- referencelist.reference.resource_attribute);
-
- referencelist.reference.resource_attribute=0;
-
- if(verbose) fprintf(stderr,
- "data offset = %lu (absolute %lu)\n",
- referencelist.reference.data_offset,
- resourceheader.data_offset+
- referencelist.reference.data_offset);
-
- if(read_resource(fi,resourceheader.data_offset+
- referencelist.reference.data_offset,fo))
- return(1);
- }
-
- return(0);
- }
-
-
- /*
- ** Read resource data from given offset of file, decode Adobe coding
- */
- read_resource(FILE *fi,unsigned long offset,FILE *fo) {
- unsigned long size;
- int c;
-
- fseek(fi,offset,0);
- if(fread(&size,1,sizeof(size),fi)!=sizeof(size)) return(1);
- if(!size) return(0);
- if(verbose)
- fprintf(stderr,"\tlength = %lu\n",size);
-
- c=fgetc(fi);
-
- /* This bit is a wart. I really don't know why it's needed! */
- /* Unfortunately, the results will be incorrect without it */
- fgetc(fi); size--;
-
- switch(c) {
- /* Comment resource, just ignore */
- case 0:
- break;
- /* ASCII text, copy directly to output */
- case 1:
- while(--size)
- if((c=fgetc(fi))==-1)
- return(1);
- else if(c=='\r')
- fputc('\n',fo);
- else
- fputc(c,fo);
- break;
- /* Binary data, convert to hexadecimal */
- case 2:
- for(c=1; --size; c++)
- fprintf(fo,(c%32)?"%02X":"%02X\n",fgetc(fi));
- fputc('\n',fo);
- break;
- /* End of file marker -- we actually should send ^D at this point? */
- case 3:
- break;
- /* Font program is in data fork -- what the hell do we do to this? */
- /* (we'll assume calling script has handled this bit) */
- case 4:
- fprintf(stderr,"Font program is in data fork\n");
- /* Flow thru: Hit EOF -- a error */
- case -1:
- default:
- return(1);
- /* End-of-font marker resource */
- case 5:
- break;
- }
- return(0);
- }
-
-
- /*
- ** Read a PC pfb format file
- */
- pcfont(FILE *fi,FILE *fo) {
- int c;
- unsigned long size;
-
- while((c=fgetc(fi))==128) {
- c=fgetc(fi);
- size=fgetc(fi);
- size+=fgetc(fi)<<(8);
- size+=fgetc(fi)<<(8+8);
- size+=fgetc(fi)<<(8+8+8);
-
- if(verbose) fprintf(stderr,"segment type = %u, length = %lu\n",c,size);
- switch(c) {
- /* ASCII text, copy directly to output */
- case 1:
- while(size--)
- if((c=fgetc(fi))==-1)
- return(1);
- else if(c=='\r')
- fputc('\n',fo);
- else
- fputc(c,fo);
- break;
- /* Binary data, convert to hexadecimal */
- case 2:
- for(c=1; size--; c++)
- fprintf(fo,(c%32)?"%02X":"%02X\n",fgetc(fi));
- fputc('\n',fo);
- break;
- /* End of file marker or real EOF */
- case 3:
- return(0);
- /* Hit EOF or anything else -- a error */
- default:
- return(1);
- }
- }
-
- if(verbose && c!=-1) fprintf(stderr,"read illegal byte = 0x%02x\n",c);
- return(c!=-1);
- }
-